#include <types.h>
#include <sys_config.h>

#include <api/libc/string.h>
#include <api/libc/printf.h>

#include <api/libtsi/p_search.h>

#include <api/libtsi/si_types.h>
#include <api/libtsi/si_descriptor.h>
#include <api/libtsi/si_section.h>

#include <api/libsi/si_module.h>
#include <api/libsi/psi_pmt.h>
#include <api/libsi/desc_loop_parser.h>
#include <api/libsi/si_service_type.h>

#ifdef AUTO_OTA
#include <api/libota/lib_ota.h>
#endif

#define PP_DEBUG_LEVEL			0
#if (PP_DEBUG_LEVEL>0)
#define PP_PRINTF			libc_printf
#else
#define PP_PRINTF(...)			do{}while(0)
#endif

//Ben 130903#1
#if(defined(EWS_FUNCTION))
#define EWS_PMT_PRINTF		PRINTF	//libc_printf
#endif
//Ben 130903#1

#ifdef VIDEO_SEAMLESS_SWITCHING
static INT32 video_control_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	struct pmt_es_info *es = (struct pmt_es_info *)priv;
	
	es->video_control = (*desc|0x1);
	
	return SI_SUCCESS;
}
#endif

static INT32 iso639_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	UINT8 i = 0, j = 0;
	UINT8 k = 0;
    UINT8 index = 0;
	struct pmt_es_info *es = (struct pmt_es_info *)priv;
#ifdef AUDIO_DESCRIPTION_SUPPORT
	UINT8 a_chan_cnt = 0; // audio channel count, 
#endif
	//es->lang size is only 3 byte, but some abnomal component audio has more than 1 language
	for( i = 0; i < len; i += 4)
	{
        if((k+3) < ES_INFO_MAX_LANG_SIZE)
        {
		    //MEMCPY(&es->lang[k], (desc + i), 3);
		    for (j=i; j<i+3; j++) {
                if ( (*(desc+j) >= 'a' && *(desc+j) <= 'z')||(*(desc+j) >= 'A' && *(desc+j) <= 'Z'))
                    es->lang[index++] = *(desc+j);
                else
                    es->lang[index++] = 'a';
		    }
#ifdef AUDIO_DESCRIPTION_SUPPORT
			if (a_chan_cnt == 0) // we need only one audio_type for AD
				es->audio_type[a_chan_cnt++] = desc[i+3];
#endif
		    k += 3;
        }
        else
        {
            break;
        }
	}
	return SI_SUCCESS;
}

static INT32 loop1_ca_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	PROG_INFO *info = (PROG_INFO *)priv;
#ifdef LEGACY_HOST_SUPPORT
	INT32 desc_offset = 4;
	UINT8 desc_tag = 0;
	INT32 desc_len = 0;
#endif	

	if (info->CA_count < P_MAX_CA_NUM)
	{
		info->CA_info[info->CA_count].CA_system_id = (desc[0]<<8) |desc[1];
		info->CA_info[info->CA_count].CA_pid = ((desc[2]&0x1F)<<8) |desc[3];
		PP_PRINTF("PMT loop1 ca_desc_handler, ca_sysid=0x%x,pid=%d,CA_count=%d\n",
			info->CA_info[info->CA_count].CA_system_id,info->CA_info[info->CA_count].CA_pid,info->CA_count+1);
#ifdef LEGACY_HOST_SUPPORT
		while(desc_offset<len)
		{
			desc_tag = desc[desc_offset];
			desc_len = desc[desc_offset+1];
			if(desc_tag!=0x8C)
			{
				desc_offset = desc_offset+2+desc_len;
			}
			else
			{
				//use the CA_pid bit15 to sign the HD+ service
				info->hdplus_flag= 1;
				break;
			}
		}
#endif		

		info->CA_count++;
	}
	else
	{
		PP_PRINTF("%s: ca count %d full!\n",__FUNCTION__,info->CA_count);
	}
	return SI_SUCCESS;
}

#ifdef PARENTAL_SUPPORT

UINT8 g_pmt_rating =0;

static  INT32 loop1_pr_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	PROG_INFO *info = (PROG_INFO *)priv;
	UINT8 country_code[3];
	UINT8 rating=0;

	//do
	//{
		country_code[0] = desc[0];
		country_code[1] = desc[1];
		country_code[2] = desc[2];
		g_pmt_rating=desc[3];	
		PP_PRINTF("country_code: %c%c%c\n",country_code[0],country_code[1],country_code[2]);
		PP_PRINTF("rating: %d\n",rating);

		//desc+= 4;

	//} while (p < desc+len);

	return SUCCESS;
}

UINT32 pmt_get_rating(void)
{	
	return g_pmt_rating;
}

#endif
static INT32 loop2_ca_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	struct pmt_es_info *info = (struct pmt_es_info *)priv;

	if (info->cas_count < P_MAX_CA_NUM)
	{
		info->cas_sysid[info->cas_count]= (desc[0]<<8) |desc[1];
		info->cas_pid[info->cas_count] = ((desc[2]&0x1F)<<8) |desc[3];
		PP_PRINTF("PMT loop2 ca_desc_handler, ca_sysid=0x%x,pid=%d,CA_count=%d\n",
			info->cas_sysid[info->cas_count],info->cas_pid[info->cas_count],info->cas_count+1);
		info->cas_count++;
	}
	else
	{
		PP_PRINTF("%s: ca count %d full!\n",__FUNCTION__,info->cas_count);
	}
	return SI_SUCCESS;
}

static INT32 com_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	UINT8 stream_content;
	UINT8 component_type;
	UINT8 compontent_tag;
	struct pmt_es_info *info = (struct pmt_es_info *)priv;

	stream_content = desc[2]&0x0f;

	if (stream_content == 0x01)			// MPEG2 video
		;
	else if (stream_content == 0x02)	// AAC MPEG2 audio
		info->audio_com_tag = desc[4];
	else if (stream_content == 0x05)	// H264/AVC video
		;
	else if (stream_content == 0x06)	// HE-AAC MPEG4 audio
		info->audio_com_tag = desc[4];

	return SI_SUCCESS;
}

//Ben 130903#1
#if(defined(EWS_FUNCTION))
static INT32 Stream_identifier_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	struct pmt_es_info *info = (struct pmt_es_info *)priv;
	
	info->audio_com_tag = desc[0];
	EWS_PMT_PRINTF("%s: audio_com_tag=%d pid=%x stream_type=%d\n",__FUNCTION__,info->audio_com_tag,info->pid,info->stream_type);
	return SI_SUCCESS;
}

static INT32 Adap_field_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	struct pmt_es_info *info = (struct pmt_es_info *)priv;
	info->adap_field_data_id = desc[0];
	EWS_PMT_PRINTF("%s: adap_field_data_id=%d pid=%d\n",__FUNCTION__,info->adap_field_data_id,info->pid);
	return SI_SUCCESS;
}

static INT32 Ancillary_data_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	struct pmt_es_info *info = (struct pmt_es_info *)priv;
	info->ancillary_data_id = desc[0];
	EWS_PMT_PRINTF("%s: ancillary_data_id=%d pid=%d\n",__FUNCTION__,info->ancillary_data_id,info->pid);
	return SI_SUCCESS;
}
#endif
//Ben 130903#1

#if defined (_MHEG5_V20_ENABLE_)
static INT32 data_broadcastid_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	struct pmt_es_info *es = (struct pmt_es_info *)priv;

	UINT8 *data_boardcast_loop_start;
	UINT8 *application_data_start_byte;
	UINT8 data_boardcast_loop_len, application_data_length;
	UINT8 boot_priority_hint;
	UINT8 previous_hint = 0;
	UINT16 data_broadcast_id;

	es->got_NB = FALSE;
	es->boot_info_length = 0;
	es->NB_version = 0;
	es->NB_action = 0xFF;
	es->boot_info_start_byte = NULL;

	data_boardcast_loop_start = desc + 2;
	data_boardcast_loop_len = len-2;
	data_broadcast_id = desc[0]<<8 | desc[1];

	if (data_broadcast_id == 0x0106)
		es->stat |= MHEG5_BROADCAST_ID_EXIST; 
	if (data_broadcast_id != 0x0106 || data_boardcast_loop_len==0)
	{
		return SI_SUCCESS;
	}
	while (data_boardcast_loop_len>0)
	{
		boot_priority_hint = data_boardcast_loop_start[2];
		application_data_length = data_boardcast_loop_start[3];
		
		if (application_data_length==0)
		{
			break;
		}
		application_data_start_byte = data_boardcast_loop_start+4;
		if (boot_priority_hint >= previous_hint)
		{						 
			previous_hint = boot_priority_hint;
			if (application_data_start_byte[0]==0x1)
			{
				es->got_NB = TRUE;
				es->boot_info_length = application_data_start_byte[1] - 2;
				es->NB_version = application_data_start_byte[2];
				es->NB_action = application_data_start_byte[3];
				es->boot_info_start_byte = application_data_start_byte+4;
			}
		}
		data_boardcast_loop_start += (application_data_length+4);
		data_boardcast_loop_len -= (application_data_length+4);
	}
	return SI_SUCCESS;
}
#endif
#ifdef _MHEG5_ENABLE_
/*
 * to get the carousel_id
 */
static INT32 carousel_id_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	struct pmt_es_info *es = (struct pmt_es_info *)priv;

	es->carousel_id = (desc[0]<<24)|(desc[1]<<16)|(desc[2]<<8)|desc[3];

	return SI_SUCCESS;
}

/*
 * process data_broadcast_id_descriptor
 */
static INT32 data_broadcastid_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	struct pmt_es_info *es = (struct pmt_es_info *)priv;

	UINT8 *data_boardcast_loop_start;
	UINT8 *application_data_start_byte;
	UINT8 data_boardcast_loop_len, application_data_length;
	UINT8 boot_priority_hint;
	UINT8 previous_hint = 0;
	UINT16 data_broadcast_id;

	es->got_NB = FALSE;
	es->boot_info_length = 0;
	es->NB_version = 0;
	es->NB_action = 0xFF;
	es->boot_info_start_byte = NULL;

	data_boardcast_loop_start = desc + 2;
	data_boardcast_loop_len = len-2;
	data_broadcast_id = desc[0]<<8 | desc[1];

	if (data_broadcast_id == 0x0106)
		es->stat |= MHEG5_BROADCAST_ID_EXIST; 
	if (data_broadcast_id != 0x0106 || data_boardcast_loop_len==0)
	{
		return SI_SUCCESS;
	}
	while (data_boardcast_loop_len>0)
	{
		boot_priority_hint = data_boardcast_loop_start[2];
		application_data_length = data_boardcast_loop_start[3];
		
		if (application_data_length==0)
		{
			break;
		}
		application_data_start_byte = data_boardcast_loop_start+4;
		if (boot_priority_hint >= previous_hint)
		{						 
			previous_hint = boot_priority_hint;
			if (application_data_start_byte[0]==0x1)
			{
				es->got_NB = TRUE;
				es->boot_info_length = application_data_start_byte[1] - 2;
				es->NB_version = application_data_start_byte[2];
				es->NB_action = application_data_start_byte[3];
				es->boot_info_start_byte = application_data_start_byte+4;
			}
		}
		data_boardcast_loop_start += (application_data_length+4);
		data_boardcast_loop_len -= (application_data_length+4);
	}
	return SI_SUCCESS;
}
#endif
#if 0
INT32 ttx_desc(UINT8 tag, UINT8 desc_length, UINT8 *desc, void *priv)
{
	UINT8 lang_idx;
	UINT8 mag;
	UINT16 page=100;
	UINT8 teletext_type;
	struct pmt_es_info *es = (struct pmt_es_info *)priv;
    
	UINT16 pid = es->pid;


	if(pid <0x20 || pid == 0x1fff)		
	{
		es->ttx_lang_num = 0;
		es->ttx_subt_lang_num = 0;
		return SI_SUCCESS;	
	}
	
	while(desc_length>=5)
	{
		
		mag = (desc[3]&0x07)?(desc[3]&0x07):8;
		page = (desc[4]>>4)*10 + (desc[4]&0x0f);
		page += (mag * 100);
		teletext_type = desc[3]>>3;
        //libc_printf("mag=%d,page=%d,teletext_type=%d,g_init_page_num=%d\n",mag,page,teletext_type,g_init_page_num);
		if(teletext_type == 1)//initial teletext page
		{
			if(es->ttx_lang_num >= TTX_SUBT_LANG_NUM)
				return SI_SUCCESS;
			
			for(lang_idx = 0; lang_idx < es->ttx_lang_num; lang_idx++)
			{
				if((desc[0] == es->init_page[lang_idx].lang[0]) 
					&&(desc[1] == es->init_page[lang_idx].lang[1]) 
					&&(desc[2] == es->init_page[lang_idx].lang[2])
					&&(pid == es->init_page[lang_idx].pid)
					&&(page == es->init_page[lang_idx].page))
					break;
			}
			if(lang_idx >= es->ttx_lang_num)
			{				
				es->init_page[es->ttx_lang_num].lang[0]=desc[0];
				es->init_page[es->ttx_lang_num].lang[1]=desc[1];
				es->init_page[es->ttx_lang_num].lang[2]=desc[2];			

				es->init_page[es->ttx_lang_num].pid = pid;
				es->init_page[es->ttx_lang_num].page = page;
				es->ttx_lang_num++;
			}
		}
		else if(teletext_type == 2 || teletext_type == 5)//subtitle teletext page & subtitle teletext page for impaired people
		{
			if(es->ttx_subt_lang_num >= TTX_SUBT_LANG_NUM)
				return SI_SUCCESS;	
			for(lang_idx = 0; lang_idx < es->ttx_subt_lang_num; lang_idx++)
			{
				if((desc[0] == es->ttx_subt_page[lang_idx].lang[0]) 
					&&(desc[1] == es->ttx_subt_page[lang_idx].lang[1]) 
					&&(desc[2] == es->ttx_subt_page[lang_idx].lang[2])
					&&(pid == es->ttx_subt_page[lang_idx].pid)
					&&(page == es->ttx_subt_page[lang_idx].page))
					break;
			}
			if(lang_idx >= es->ttx_subt_lang_num)
			{				
				es->ttx_subt_page[es->ttx_subt_lang_num].lang[0]=desc[0];
				es->ttx_subt_page[es->ttx_subt_lang_num].lang[1]=desc[1];
				es->ttx_subt_page[es->ttx_subt_lang_num].lang[2]=desc[2];		
				
				es->ttx_subt_page[es->ttx_subt_lang_num].pid = pid;
				es->ttx_subt_page[es->ttx_subt_lang_num].page = page;
				es->ttx_subt_lang_num++;
			}
            if(page==100 && es->ttx_lang_num==0)//some special streams have teletext_type=2 but they have ttx (Rating_Ter_OK.trp) by cloud
            {
                es->init_page[es->ttx_lang_num].lang[0]=desc[0];
			    es->init_page[es->ttx_lang_num].lang[1]=desc[1];
			    es->init_page[es->ttx_lang_num].lang[2]=desc[2];			

				es->init_page[es->ttx_lang_num].pid = pid;
				es->init_page[es->ttx_lang_num].page = page;
				es->ttx_lang_num++; 

                if((es->ttx_subt_lang_num == 1) && (es->ttx_subt_page[0].page == 100))
                    es->ttx_subt_lang_num = 0;//it is a wrong header, cloud
            }
		}
		desc +=5;
		desc_length -= 5;
	}


	return SI_SUCCESS;
		
}

INT32 subt_desc(UINT8 tag, UINT8 desc_length, UINT8 *desc, void *priv)
{
	UINT8 lang_idx;
	struct pmt_es_info *es = (struct pmt_es_info*)priv;
	UINT16 pid = es->pid;

	if(pid <0x20 || pid == 0x1fff)		
	{
		es->subt_lang_num = 0;
		return SI_SUCCESS;	
	}
	while(desc_length>=8)
	{
		if(es->subt_lang_num >= SUBTITLE_LANG_NUM)
			return SI_SUCCESS;	
		
		for(lang_idx = 0;lang_idx<es->subt_lang_num;lang_idx++)
		{
			if((desc[0] == es->subt_lang[lang_idx].lang[0]) 
				&&(desc[1] == es->subt_lang[lang_idx].lang[1]) 
				&&(desc[2] == es->subt_lang[lang_idx].lang[2])
				&&(desc[3] == es->subt_lang[lang_idx].subt_type)
				&&((desc[4]<<8) + desc[5] == es->subt_lang[lang_idx].com_page)
				&&((desc[6]<<8) + desc[7] == es->subt_lang[lang_idx].anci_page)
				&&(pid == es->subt_lang[lang_idx].pid))
				break;
		}
		if(lang_idx >= es->subt_lang_num)//not same with anyone of the old
		{		
			//if((desc[3]>=0x10 && desc[3]<=0x13)||(desc[3]>=0x20 && desc[3]<=0x23))
			{//en300468 table26
				es->subt_lang[es->subt_lang_num].lang[0]=desc[0];
				es->subt_lang[es->subt_lang_num].lang[1]=desc[1];
				es->subt_lang[es->subt_lang_num].lang[2]=desc[2];

				es->subt_lang[es->subt_lang_num].pid = pid;
				es->subt_lang[es->subt_lang_num].subt_type = desc[3];
				es->subt_lang[es->subt_lang_num].com_page = (desc[4]<<8) + desc[5];
				es->subt_lang[es->subt_lang_num].anci_page = (desc[6]<<8) + desc[7];
				
				es->subt_lang_num++;
			}
		}
		
		desc += 8;
		desc_length -= 8;
		
	}

    return SI_SUCCESS;
		
}
#endif
#ifdef AUTO_OTA
extern UINT32 si_get_otaconfig_oui();

INT32 databroadcastid_deschandle(UINT8 tag, UINT8 len, UINT8 *pdata, void *ppriv)
{
	INT32 ret;
	UINT8 oui_data_len, selector_len;
	UINT16 data_broadcast_id;
	UINT32 oui;
//	PMT_ESLOOP_INFO *p_info = (PMT_ESLOOP_INFO *)ppriv;
	struct pmt_es_info *p_info = (struct pmt_es_info *)ppriv;
	if(DATA_BROADCASTID_DES_TAG != tag)
	{
//		libc_printf("%s[%s] : databroadcastid tag wrong!\n", __FUNCTION__, __FILE__);
		ASSERT(0);
	}
//	dump_data(pdata-2, len+2, "databroadcastid_desc");
	data_broadcast_id = (pdata[0]<<8 | pdata[1]);
	oui_data_len = pdata[2];
	oui = (pdata[3]<<16 | pdata[4]<<8 | pdata[5]);
    //libc_printf("%s:oui = %x\n",__FUNCTION__,oui);
	if(DATABROADCASTID_ALIOTA == data_broadcast_id 
		&& (oui==si_get_otaconfig_oui()))
	{
		selector_len = pdata[8];
		AUTO_OTA_INFO *pota_info = &p_info->pmt_ssu_info.m_otainfo;
		if(selector_len >=8)
		{
			pota_info->hw_model = pdata[9]<<8 | pdata[10];
			pota_info->hw_ver = pdata[11]<<8 | pdata[12];
			pota_info->sw_model = pdata[13]<<8 | pdata[14];
			pota_info->ota_sw_version = pdata[15]<<8 | pdata[16];
		}
		pota_info->oui = oui;
	}
   
	ret = SI_SUCCESS;
	return ret;
}
#endif

#ifdef AUDIO_DESCRIPTION_SUPPORT

//#define _AD_DEBUG

#ifdef _AD_DEBUG
#define ad_debug(fmt, arg...) libc_printf(fmt, ##arg)
#define ad_error(fmt, arg...) \
    do { \
        libc_printf("Error: %s line %d: "fmt, __FILE__, __LINE__, ##arg); \
    } while (0)
#else
#define ad_debug(...)	do{} while(0)
#define ad_error(...)	do{} while(0)
#endif

//Be moved to si_descriptor.h.
/* refer to ETSI EN 300 468 */
//enum descriptor_tag_extension {
//	IMAGE_ICON_DESCRIPTOR				= 0x00,
//	CPCM_DELIVERY_SIGNALLING_DESCRIPTOR	= 0x01,
//	CP_DESCRIPTOR						= 0x02,
//	CP_IDENTIFIER_DESCRIPTOR			= 0x03,
//	T2_DELIVERY_SYSTEM_DESCRIPTOR		= 0x04,
//	SH_DELIVERY_SYSTEM_DESCRIPTOR		= 0x05,
//	SUPPLEMENTARY_AUDIO_DESCRIPTOR		= 0x06,
//	NETWORK_CHANGE_NOTIFY_DESCRIPTOR	= 0x07,
//	MESSAGE_DESCRIPTOR					= 0x08,
//	TARGET_REGION_DESCRIPTOR			= 0x09,
//	TARGET_REGION_NAME_DESCRIPTOR		= 0x0A,
//	SERVICE_RELOCATED_DESCRIPTOR		= 0x0B,
//};

/* only handle the Supplementary audio descriptor */
static INT32 extension_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	struct pmt_es_info *es = (struct pmt_es_info *)priv;

	ad_debug("\t extension descriptor len: 0x%X\n", len);
	ad_debug("\t descriptor_tag_extension: 0x%X\n", desc[0]);

	if (desc[0] == SUPPLEMENTARY_AUDIO_DESCRIPTOR) // descriptor_tag_extension
	{
		es->SAD_present = 1;
		es->SAD_mix_type = (desc[1] >> 7) & 1;
		es->SAD_editorial_classification = (desc[1] >> 2) & 0x1f;
		es->SAD_language_code_present = desc[1] & 1;
		if (es->SAD_language_code_present)
			MEMCPY(es->SAD_lang, &desc[2], ES_INFO_ONE_LANG_SIZE);

#ifdef _AD_DEBUG
		ad_debug("\t Supplementary audio descriptor\n");
		ad_debug("\t\t mix_type: 0x%X\n", (desc[1] >> 7) & 1);
		ad_debug("\t\t editorial_classification: 0x%X\n", (desc[1] >> 2) & 0x1f);
		ad_debug("\t\t reserved: %d\n", (desc[1] >> 1) & 1);
		ad_debug("\t\t language_code_present: %d\n", desc[1] & 1);
		if (es->SAD_language_code_present)
		{
			ad_debug("\t\t ISO_639_language_code 0: 0x%X(%c)\n", desc[2], desc[2]);
			ad_debug("\t\t ISO_639_language_code 1: 0x%X(%c)\n", desc[3], desc[3]);
			ad_debug("\t\t ISO_639_language_code 2: 0x%X(%c)\n", desc[4], desc[4]);
		}
#endif
	}

	return SI_SUCCESS;
}


static int audio_info_amend(struct pmt_es_info *es)
{
	if (!es->SAD_present)
		return 0;

	ad_debug("audio info before amend: %c%c%c, 0x%X, %d, %d\n",
		es->lang[0], es->lang[1], es->lang[2], es->audio_type[0],
		es->SAD_mix_type, es->SAD_editorial_classification);
	
	if (es->SAD_language_code_present)
		MEMCPY(es->lang, es->SAD_lang, ES_INFO_ONE_LANG_SIZE);
	
	if (es->SAD_mix_type == 0)
	{
		if (es->SAD_editorial_classification == 1)
		{
#ifdef _AD_DEBUG
			if (es->audio_type[0] != 0x03)
			{
				ad_error("Inconsistent audio info\n");
			}
#endif
			es->audio_type[0] = AUDIO_TYPE_AD_RECEIVER_MIXED;
		}
	}
	else if (es->SAD_mix_type == 1)
	{
		switch (es->SAD_editorial_classification)
		{
			case 0:
#ifdef _AD_DEBUG
				if (es->audio_type[0] != 0x00 && es->audio_type[0] != 0x01)
				{
					ad_error("Inconsistent audio info\n");
				}
#endif
				es->audio_type[0] = AUDIO_TYPE_MAIN_AUDIO;
				break;
			case 1:
#ifdef _AD_DEBUG
				if (es->audio_type[0] != 0x00 && es->audio_type[0] != 0x01 &&
					es->audio_type[0] != 0x03)
				{
					ad_error("Inconsistent audio info\n");
				}
#endif
				es->audio_type[0] = AUDIO_TYPE_AD_BROADCAST_MIXED;
				break;
			case 2:
#ifdef _AD_DEBUG
				if (es->audio_type[0] != 0x02)
				{
					ad_error("Inconsistent audio info\n");
				}
#endif
				es->audio_type[0] = AUDIO_TYPE_CLEAN_AUDIO;
				break;
			case 3:
#ifdef _AD_DEBUG
				if (es->audio_type[0] != 0x00 && es->audio_type[0] != 0x01 &&
					es->audio_type[0] != 0x03)
				{
					ad_error("Inconsistent audio info\n");
				}
#endif
				es->audio_type[0] = AUDIO_TYPE_SPOKEN_SUBTITLE;
				break;
			default:
				break;
		}
	}

	ad_debug("audio info after amend:  %c%c%c, 0x%X, %d, %d\n",
		es->lang[0], es->lang[1], es->lang[2], es->audio_type[0],
		es->SAD_mix_type, es->SAD_editorial_classification);

	return 0;
}

#endif /* AUDIO_DESCRIPTION_SUPPORT */

static struct desc_table pmt_loop1[] = {
	{
		CA_DESCRIPTOR,
		ES_CA_EXIST_BIT,
		loop1_ca_desc_handle,
	},
#ifdef PARENTAL_SUPPORT
	{
		PARENTAL_RATING_DESCRIPTOR,
		0,//ES_PR_EXIST_BIT,
		loop1_pr_desc_handle,
	},
#endif
};

/*
 * please pay attention that this array should be sorted by tag in ascend order.
 * other wise the desc_loop_parser won't work out!!!
 */
static struct desc_table pmt_loop2[] = {
	{	
		DTS_REGST_DESC, 
		ES_DTS_EXIST_BIT,
		NULL,
	},
	{
		CA_DESCRIPTOR,
		ES_CA_EXIST_BIT,
		loop2_ca_desc_handle,
	},
	{
		ISO_639_LANGUAGE_DESCRIPTOR, 
		ES_ISO639_EXIST_BIT,
		iso639_desc_handle,
	},
#ifdef _MHEG5_ENABLE_
	{
		CAROUSEL_ID_DES_TAG,
		ES_CAROUSEL_ID_EXIST_BIT,
		carousel_id_desc_handle,
	},
#endif
//#if (MPEG4_DEFINITION == SYS_FUNC_ON)||(SYS_PROJECT_FE == PROJECT_FE_DVBS)
	{
		MPEG_4_VIDEO_TAG, 
		ES_MPEG4_VIDEO_EXIST_BIT,
		NULL,
	},
	{
		MPEG_4_AUDIO_TAG, 
		ES_MPEG4_AUDIO_EXIST_BIT,
		NULL,
	},
	{
		AVC_VIDEO_TAG,
		ES_AVC_VIDEO_EXIST_BIT,
		NULL,
	},
//#endif	
	//Ben 130903#1
	#ifndef EWS_FUNCTION
	{
		COMPONENT_DESCRIPTOR,
		ES_COM_TAG_EXIST_BIT,
		com_desc_handle,
	},
	#endif
	//Ben 130903#1
#if (defined(ISDBT_CC)&&ISDBT_CC == 1)
	{
		STREAM_IDENTIFIER_DESCRIPTOR,
		ES_STREAM_ID_EXIST_BIT,
		NULL,
	},			
#endif

//Ben 130903#1
#if(defined(EWS_FUNCTION))
	{
		STREAM_IDENTIFIER_DESCRIPTOR,
		ES_STREAM_ID_EXIST_BIT,
		Stream_identifier_desc_handle,
	},
	{
		ADAPTATION_FIELD_DATA_DESCRIPTOR,
		ES_AD_FIELD_EXIST_BIT,	
		Adap_field_desc_handle,
	},
	{
		ANCILLARY_DATA_DESCRIPTOR,
		ES_AD_DES_EXIST_BIT,	
		Ancillary_data_desc_handle,
	},
#endif
//Ben 130903#1
	{
		TELTEXT_DESCRIPTOR,
		ES_TTX_EXIST_BIT,
		NULL,
	},
	{
		SUBTITLE_DESCRIPTOR,
		ES_SUB_EXIST_BIT,
		NULL,
	},
#ifdef AUTO_OTA
	{
		DATA_BROADCASTID_DES_TAG,
		ES_DTS_EXIST_BIT,
		databroadcastid_deschandle,
	},
#endif
#if (defined(_MHEG5_ENABLE_) ||defined(_MHEG5_V20_ENABLE_))
	{
		DATA_BROADCASTID_DES_TAG,
		ES_DATA_BROADCASTID_EXIST_BIT,
		data_broadcastid_desc_handle,
	},
#endif
	{
		AC3_DESCRIPTOR,
		ES_AC3_EXIST_BIT,
		NULL,
	},
	{
		ENHANCED_AC3_DESCRIPTOR,
		ES_EAC3_EXIST_BIT,
		NULL,
	},		
	{
		AAC_DESCRIPTOR,
		ES_AAC_EXIST_BIT,
		NULL,
	},
#if 0
	{
		TELTEXT_DESCRIPTOR,
		ES_TTX_EXIST_BIT,
		ttx_desc,
	},
	{
		SUBTITLE_DESCRIPTOR,
		ES_SUB_EXIST_BIT,
		subt_desc,
	},
#endif
#ifdef VIDEO_SEAMLESS_SWITCHING
	{
		ISDBT_VIDEO_DECODE_CONTROL_DESCRIPTOR,
		ES_V_CTRL_EXIST_BIT,
		video_control_desc_handle,
	},
#endif
#if (defined(ISDBT_CC)&&ISDBT_CC == 1)
	{
		ISDBT_DATA_COMPONENT_DESCRIPTOR,
		ES_DATA_COMP_EXIST_BIT,
		NULL,
	},			
#endif	
#ifdef ATSC_SUBTITLE_SUPPORT   			
{
		ATSC_EXTENDED_VIDEO_DESCRIPTOR, 
		ES_EXTENDED_VIDEO_DESC_EXIST_BIT,
		NULL,
},
#endif
#ifdef AUDIO_DESCRIPTION_SUPPORT
	{
		EXTENSION_DESCRIPTOR, 
		ES_EXTENSION_DESC_EXIST_BIT,
		extension_desc_handle,
	},

#endif
};

static BOOL append_audio_pid(struct pmt_es_info *es, PROG_INFO *info, UINT16 attr)
{
	BOOL ret;
	UINT32 audio_cnt;
	UINT8 j = 0;
	UINT8 *lang = es->lang;

#ifdef AUDIO_DESCRIPTION_SUPPORT
	audio_info_amend(es);
#endif

	audio_cnt = info->audio_count;
	if(audio_cnt < P_MAX_AUDIO_NUM) {
#ifdef CONAX_AUDIO_LAN_USE
		if (lang[0]&&lang[1]&&lang[2]) {
			MEMCPY(info->audio_lang[audio_cnt], lang, 3);
			info->audio_pid[audio_cnt] = es->pid|attr;
			audio_cnt ++;
			info->audio_count = audio_cnt;
		} else {
			MEMSET(info->audio_lang[audio_cnt], 0, 3);
		}
		if (lang[3]&&lang[4]&&lang[5]) {
			MEMCPY(info->audio_lang[audio_cnt], (lang + 3), 3);
			info->audio_pid[audio_cnt] = es->pid|attr;
			audio_cnt ++;
			info->audio_count = audio_cnt;
		} else {
			MEMSET(info->audio_lang[audio_cnt], 0, 3);
		}
		if ((lang[0]&&lang[1]&&lang[2]) == 0)
		{
			info->audio_pid[audio_cnt] = es->pid|attr;
			info->audio_count = audio_cnt+1;
		}
#else
		info->audio_pid[audio_cnt] = es->pid|attr;
		//Ben 130903#1
		info->audio_com_tag[audio_cnt] = es->audio_com_tag;
		#if (defined(EWS_FUNCTION))
		info->accillary_data[audio_cnt] = es->ancillary_data_id;
		//libc_printf("%s: audio_com_tag=%d adap_field_id=%d\n",__FUNCTION__,es->audio_com_tag,es->adap_field_id);	
		#endif
		//Ben 130903#1
		
		if (lang[0]&&lang[1]&&lang[2]) {
			MEMCPY(info->audio_lang[audio_cnt], lang, 3);
		} else {
			MEMSET(info->audio_lang[audio_cnt], 0, 3);
		}
		
	#ifdef AUDIO_DESCRIPTION_SUPPORT
		info->audio_type[audio_cnt] = es->audio_type[0];
	#endif

	#ifdef NL_BZ
		if (lang[3]&&lang[4]&&lang[5]) {
			MEMCPY(info->audio_lang[audio_cnt + 3], (lang + 3), 3);
		}
		else {
			MEMSET(info->audio_lang[audio_cnt + 3], 0, 3);
		}
	#endif				

		info->audio_count = audio_cnt+1;
	
	#ifdef AUDIO_CHANNEL_LANG_SUPPORT
		if ((info->audio_count < P_MAX_AUDIO_NUM) &&
			(lang[3] && lang[4] && lang[5]))
		{	// add one more audio pid for the channel language
			MEMCPY(info->audio_lang[info->audio_count], (lang + 3), 3);
			info->audio_pid[info->audio_count] = es->pid | attr;
		#ifdef AUDIO_DESCRIPTION_SUPPORT
			info->audio_type[info->audio_count] = es->audio_type[0];
		#endif
			info->audio_count++;
		}
	#endif
#endif
		PP_PRINTF("+aud_pid=%d\n", es->pid);
		
		ret = TRUE;
	} else {
		PP_PRINTF("-aud_pid=%d\n", es->pid);
		ret = FALSE;
	}
	PP_PRINTF("lang code: %c%c%c\n", lang[0], lang[1], lang[2]);
	
#ifdef AUDIO_DESCRIPTION_SUPPORT
	ad_debug("%s() audio type: 0x%X\n", __FUNCTION__, es->audio_type[0]);
#endif

	return ret;
}

/*
  * Name	: psi_parse_loop2
  * Description	: parse pmt second loop.
  * Parameter   : 
  *	INT8 *buff       :seciton buffer
  *     INT16 buff_len   :buffer length
  * Return        :
  */
static INT32 pmt_parse_loop2(UINT8 *pmt, UINT16 pmt_len, PROG_INFO *p_info,
	INT32 max_es_nr)
{
	INT32 ret, es_cnt;
	UINT32 i, loop_len;
	struct pmt_stream_info *info;
	struct pmt_es_info es;
	UINT32 loop1_len = ((pmt[10]<<8)|pmt[11])&0x0FFF;
	UINT16 invalid_flag = 1;
	UINT32 j=0;
	UINT8 k=0;

#ifdef _MHEG5_ENABLE_
	UINT16 boot_carousel_pid; 
	UINT32 carousel_id;
	BOOL reboot = TRUE;
	mheg_get_boot_carousel_query_para(&boot_carousel_pid,&carousel_id);
//	libc_printf("boot_carousel_pid: 0x%X, carousel_id: 0x%X\n",boot_carousel_pid,carousel_id);
#endif
	PP_PRINTF("\n %s(): es stream :\n",__FUNCTION__);
	for(es_cnt=0, i = sizeof(struct pmt_section)-4+loop1_len;i < (UINT32)pmt_len-4;
		i += sizeof(struct pmt_stream_info)+loop_len)
	{
		info = (struct pmt_stream_info *)(pmt+i);
		MEMSET(&es, 0, sizeof(struct pmt_es_info));
		es.stream_type = info->stream_type;
		es.pid = SI_MERGE_HL8(info->elementary_pid);
		loop_len = SI_MERGE_HL8(info->es_info_length);	

		ret = desc_loop_parser(info->descriptor, loop_len, 
			pmt_loop2, ARRAY_SIZE(pmt_loop2), &es.stat, (void *)&es);

		if (ret != SI_SUCCESS)
			PP_PRINTF("%s: desc_loop_parser error, error= %d\n", ret);

#ifdef AUTO_OTA
//		if((ISO_13818_6_TYPE_B==pbuf[0])
		if((ISO13818_6_TYPE_B == es.stream_type)
			&&(0 != ((1<<ES_DTS_EXIST_BIT)&es.stat))
			&& (es.pmt_ssu_info.m_otainfo.oui == si_get_otaconfig_oui()
//			&& (get_ota_upgrade_found() == FALSE)
			))
			{//if stream type is ISO_13818_6_TYPE_B, data broadcast id desc is exist and oui is match
				p_info->p_esloopinfo.pmt_ssu_info.stream_type = es.stream_type;
				p_info->p_esloopinfo.pmt_ssu_info.ssu_pid = es.pid;
				p_info->p_esloopinfo.pmt_ssu_info.m_otainfo.oui = es.pmt_ssu_info.m_otainfo.oui;
				ret = SI_SUCCESS;
				invalid_flag = 0;
				break;
			}
#endif

		if (es.stat&ES_CA_EXIST)
		{
			//check if current es ca system is same with those recorded ones
			for(j=0;j<es.cas_count;j++)
			{
//fix BUG17636, to get all ecm pids
/*				for(k=0; k<p_info->CA_count; k++)
				{
					if(p_info->CA_info[k].CA_system_id==es.cas_sysid[j])
					{
						PP_PRINTF("es pid=%d, ca count=%d, cas_sysid[%d]=0x%x has same ca sysid with p_info->CA_info[%d]!\n"
						, es.pid, es.cas_count, j,es.cas_sysid[j], k);
						break;
					}
				}
				if( k==p_info->CA_count)*/
				{
					if (p_info->CA_count < P_MAX_CA_NUM)
					{
						p_info->CA_info[p_info->CA_count].CA_system_id = es.cas_sysid[j];
						p_info->CA_info[p_info->CA_count].CA_pid = es.cas_pid[j];
						p_info->CA_count++;
					}
					else
					{
						PP_PRINTF("pmt_parse_loop2: ca system id count %d full!\n",p_info->CA_count);
						break;
					}
				}
			}
		}
//#if (SYS_PROJECT_FE == PROJECT_FE_DVBS)
		//check if the stream include h264 video
		if ((es.stat&ES_AVC_VIDEO_EXIST) && (es.stream_type != 0x02) ) //fix special stream only have H.264 descriptor, actually,this stream is mpeg2 video 
		{
			p_info->avc_video_exist = 1;
		}

		//check if the stream include mpeg4 video
		if (es.stat&ES_MPEG4_VIDEO_EXIST)
		{
			p_info->mpeg_4_video_exist = 1;
		}
//#endif
	#if 0
		if(es.stat&ES_SUB_EXIST)
		{
			p_info->subt_lang_num = es.subt_lang_num;
			MEMCPY(p_info->subt_lang, es.subt_lang, sizeof(p_info->subt_lang));
		}
		if(es.stat&ES_TTX_EXIST)
		{
			p_info->ttx_lang_num = es.ttx_lang_num;
			MEMCPY(p_info->init_page, es.init_page, sizeof(p_info->init_page));
			p_info->ttx_subt_lang_num = es.ttx_subt_lang_num;
			MEMCPY(p_info->ttx_subt_page, es.ttx_subt_page, sizeof(p_info->ttx_subt_page));
		}
	#endif

#ifdef RAPS_SUPPORT
    if(p_info->prog_number == raps_get_sevice_id() && p_info->pmt_pid == raps_get_pmt_pid())
    {
        raps_set_data_pid(es.pid);
    }
#endif   

#ifdef VIDEO_SEAMLESS_SWITCHING
		if (es.stat&ES_V_CTRL_EXIST_BIT)
		{
			p_info->video_control = es.video_control;
		}
#endif

//Ben 130903#1
#if (defined(EWS_FUNCTION))
		if(es.stat&ES_AD_FIELD_EXIST_BIT)
		{
			p_info->adap_field_id = es.adap_field_data_id;
		}
#endif	
//Ben 130903#1	


        PP_PRINTF("es stream type=%d\n",es.stream_type);
		switch(es.stream_type)
		{
			case MPEG1_AUDIO_STREAM:
			case MPEG2_AUDIO_STREAM:
				if (TRUE == append_audio_pid(&es, p_info, 0))
					invalid_flag = 0;
				break;
#ifdef ATSC_SUBTITLE_SUPPORT                
            case ATSC_SUBT_STREAM:
                if (p_info->subtitle_pid == PSI_STUFF_PID)
                {
                    p_info->subtitle_pid = es.pid;
                    invalid_flag = 0;
                }
              // subt_one_lang(es.pid,es.lang);
                break;
#endif
			case PRIVATE_DATA_STREAM:
			//case MPEG_AAC_STREAM:
			//case AC3_AUDIO_STREAM:
				if(es.stat&ES_TTX_EXIST)
					p_info->teletext_pid = es.pid;
				else if(es.stat&ES_SUB_EXIST)
					p_info->subtitle_pid = es.pid;
#ifdef AC3DEC
				else if((es.stat&ES_AC3_EXIST)&&(TRUE == append_audio_pid(&es, p_info,AC3_DES_EXIST)))
				{				
					//if(es.stream_type == AC3_AUDIO_STREAM)
					//p_info->prog_number +=1;
					invalid_flag = 0;
				}
                #if 1
				else if((es.stat&ES_EAC3_EXIST)&&(TRUE == append_audio_pid(&es, p_info,EAC3_DES_EXIST)))
				{				
					//if(es.stream_type == AC3_AUDIO_STREAM)
					//p_info->prog_number +=1;				
					invalid_flag = 0;
				} 
                #endif
#endif
				break;
#ifdef AC3DEC
            case AC3_AUDIO_STREAM:
                if(TRUE == append_audio_pid(&es, p_info,AC3_DES_EXIST))
                {				
                    invalid_flag = 0;
                }
                break;
            case MPEG_AAC_STREAM:
				if(TRUE == append_audio_pid(&es, p_info,AAC_DES_EXIST))
                {						
                    invalid_flag = 0;
                }
                break;
            case MPEG_ADTS_AAC_STREAM:
                if(TRUE==append_audio_pid(&es, p_info,ADTS_AAC_DES_EXIST))
                {
                    invalid_flag = 0;
                }
                break;
#endif
			case MPEG1_VIDEO_STREAM:
			case MPEG2_VIDEO_STREAM:
			case MPEG4_VIDEO_STREAM:
		#ifdef ITALY_HD_BOOK_SUPPORT
				if(p_info->video_pid_array[p_info->video_cnt] == PSI_STUFF_PID)
				{
					p_info->av_flag = 1;
					p_info->video_pid_array[p_info->video_cnt] = es.pid;
					invalid_flag = 0;
					p_info->video_cnt++;
				}
		#else
	        	if (p_info->video_pid == PSI_STUFF_PID)
				{
//#if (SYS_PROJECT_FE == PROJECT_FE_DVBS)
					if(es.stream_type == MPEG4_VIDEO_STREAM)
						p_info->mpeg_4_video_exist = 1;
//#endif
					p_info->av_flag = 1;
					p_info->video_pid = es.pid;
					invalid_flag = 0;
				}
		#endif		
				break;
       		case H264_VIDEO_STREAM:
        #ifdef ITALY_HD_BOOK_SUPPORT
				if(p_info->video_pid_array[p_info->video_cnt] == PSI_STUFF_PID)
				{
					p_info->av_flag = 1;
					p_info->video_pid_array[p_info->video_cnt] = es.pid|H264_VIDEO_PID_FLAG;
					invalid_flag = 0;
					p_info->video_cnt++;
				}
		#else
	        	if (p_info->video_pid == PSI_STUFF_PID) 
                {
				    p_info->av_flag = 1;
				    p_info->video_pid = es.pid|H264_VIDEO_PID_FLAG;
				    invalid_flag = 0;
			    }
        #endif
                break;
#ifdef SUPPORT_AVS_DECODER				
			case AVS_VIDEO_STREAM:
			if (p_info->video_pid == PSI_STUFF_PID) 
			{
			    p_info->av_flag = 1;
			    p_info->video_pid = es.pid|AVS_VIDEO_PID_FLAG;
			    invalid_flag = 0;
			}
			break;
#endif
#ifdef ATSC_SUBTITLE_SUPPORT   			
			case DC_II_VIDEO_STREAM:  //vicky20110307	
	        		if ((p_info->video_pid == PSI_STUFF_PID)&&(es.stat&ES_EXTENDED_VIDEO_DESC_EXIST))
				if (p_info->video_pid == PSI_STUFF_PID) 
				{
					p_info->av_flag = 1;
					p_info->video_pid = es.pid;
					invalid_flag = 0;
				}
				break;
#endif	
//#if (SYS_PROJECT_FE == PROJECT_FE_DVBC)	

			#if(defined (_MHEG5_ENABLE_) || defined (_MHEG5_V20_ENABLE_))
			case ISO13818_6_TYPE_B:
			case ISO13818_6_TYPE_D:
				if ((es.stat&MHEG5_BROADCAST_ID_EXIST) != 0)
				{
					p_info->av_flag = 1;	/* set to be TV prog */
					p_info->mheg5_exist = 1;
					invalid_flag = 0;
				}
				break;	
			case 0x05:	
				invalid_flag = 0;
				break;
//			#else
			//case ISO13818_6_TYPE_A:
//			case 0x05:
//			case ISO13818_6_TYPE_B:
			//case ISO13818_6_TYPE_C:
			//case ISO13818_6_TYPE_D:
//					invalid_flag = 0;
//				break;
            #endif

//#elif(defined (_MHEG5_ENABLE_) || defined (_MHEG5_V20_ENABLE_))
//			case ISO13818_6_TYPE_B:
//			case ISO13818_6_TYPE_D:
//				if ((es.stat&MHEG5_BROADCAST_ID_EXIST) != 0)
//				{
//					p_info->av_flag = 1;	/* set to be TV prog */
//					p_info->mheg5_exist = 1;
//					invalid_flag = 0;
//				}
//				break;
//#endif

#ifdef SCTE_SUBTITLE_SUPPORT
			case 0x82:
				//soc_printf("SCTE %d",es.pid);
				for(k=0; k<p_info->scte_subt_count;k++)
				{
					if(es.pid == p_info->scte_subt_pid[k])
						break;
				}
				if(k==p_info->scte_subt_count)
				{
					p_info->scte_subt_pid[k] = es.pid;
					p_info->scte_subt_count++;
				}
				//info->descriptor: tag(1B), len(1B), lan(3B), unknow(1B)
				if((info->descriptor)[0] = 0xA && (info->descriptor)[1] >= 3)
				{
					p_info->scte_subt_lan_cnt[k] =1;
					p_info->scte_subt_lan[k][0] = (((info->descriptor)[2])<<16)|(((info->descriptor)[3])<<8)|((info->descriptor)[4]);
				}
				break;
#endif
			default:
				PP_PRINTF("es_type = 0x%x unknown!\n",__FUNCTION__, es.stream_type);
				break;
		}
		if (++es_cnt>=max_es_nr)
		{
			PP_PRINTF("es_cnt = %d exceed max_es_nr!\n",__FUNCTION__, es_cnt);
			break;
		}

#ifdef _MHEG5_ENABLE_		
		if ((es.stat&ES_CAROUSEL_ID_EXIST) != 0
			&& carousel_id != 0xffffffff
			&& es.carousel_id == carousel_id
			&& (es.stat&ES_DATA_BROADCASTID_EXIST) != 0)
		{
			reboot = FALSE;
		}
		if ((es.stat&ES_DATA_BROADCASTID_EXIST) != 0
			&& es.got_NB
			&& check_NB_version((UINT16)es.NB_version))
		{
			clear_boot_info();
			save_boot_info(es.boot_info_length, es.boot_info_start_byte, es.NB_action);
		}
#endif		
	}

#ifdef _MHEG5_ENABLE_
	if (reboot && carousel_id !=0xffffffff && boot_carousel_pid != 0xffff)
	{
//		libc_printf("carousel changing...restart \n");
		tmMHEG5ReStartCurCh();
	}
#endif

	PP_PRINTF("%s: es_cnt = %d!\n\n",__FUNCTION__, es_cnt);
	return invalid_flag? ERR_NO_PROG_INFO : SI_SUCCESS;;
}


INT32 psi_pmt_parser(UINT8 *pmt, PROG_INFO *p_info, INT32 max_es_nr)
{
	INT32 ret;
	UINT32 stat = 0;
	UINT16 len = ((pmt[1]<<8)|pmt[2])&0x0FFF;

	p_info->pcr_pid = ((pmt[8]<<8)|pmt[9])&PSI_STUFF_PID;
#ifdef ITALY_HD_BOOK_SUPPORT
       UINT8 i ;
	for(i=0; i<MAX_VIDEO_CNT; i++)
	{
		p_info->video_pid_array[i] = PSI_STUFF_PID;
	}
	p_info->video_cnt = 0;
	p_info->cur_video_pid_idx = 0;
#else
	p_info->video_pid = PSI_STUFF_PID;
#endif
	p_info->service_type = 0;
	p_info->pmt_version = (pmt[5]&0x3e)>>1;
	p_info->audio_count = 0;
	
	desc_loop_parser(pmt+12, ((pmt[10]<<8)|pmt[11])&0xFFF, 
		pmt_loop1, ARRAY_SIZE(pmt_loop1), &stat, p_info);
	
	ret = pmt_parse_loop2(pmt, len, p_info, max_es_nr);
	if(p_info->video_pid == PSI_STUFF_PID)
		p_info->video_pid = 0;
	PP_PRINTF("PMT parse ret=%d, prog num=%d, pmt pid=%d,ca count=%d,av flag=%d\n", ret,p_info->prog_number,
		p_info->pmt_pid, p_info->CA_count,p_info->av_flag);
	
	return ret;
}

#ifdef LIB_TSI3_FULL

UINT8 ecm_count = 0;
static UINT32 psi_pmt_crc_value = 0;
UINT16 ecm_pid_array[32];
void psi_pmt_get_ecm_pid(UINT8 *section, INT32 length, UINT16 param)
{
	UINT16 prog_info_len,section_len,es_info_len;
	UINT16 left_len;
	UINT8 *discriptor_pointer = NULL;
	UINT8 *discriptor_pointer2 = NULL;
	UINT8 loop_length;
	UINT16 ecm_pid = 0;
	UINT32 crc_value;
	
	section_len = ((section[1] & 0x03) << 8)|section[2];

	crc_value = (section[section_len-1] |(section[section_len]<<8)|(section[section_len+1]<<16)|(section[section_len+2]<<24));
	//pmt data not change
	if((crc_value == psi_pmt_crc_value) && (ecm_count != 0))
	{
		//DYN_PID_PRINTF("PMT section content not change, return!");
		return;
	}

	ecm_count = 0;
	
	prog_info_len = ((section[10] & 0x03) << 8)|section[11];
	left_len = section_len -9 -prog_info_len -4;

	
	discriptor_pointer = &section[12];
	discriptor_pointer2 = discriptor_pointer + prog_info_len;

	//first loop, prog_info_length
	//DYN_PID_PRINTF("		parsing pmt loop1:\n");
	while (prog_info_len > 0)
	{
		/*the CA descriptor tag*/
		if (*discriptor_pointer == 0x09)
		{
			ecm_pid = ((discriptor_pointer[4]&0x1F)<<8)|discriptor_pointer[5];
			//check card exist and match or not

			psi_pmt_crc_value = crc_value;
			if(ecm_count<32)
			{
				ecm_pid_array[ecm_count] = ecm_pid;
				ecm_count++;
			}
			else
				libc_printf("ecm_count: %d, count > 32 \n",ecm_count);

		}
		prog_info_len -= 2+discriptor_pointer[1];
		discriptor_pointer += 2+discriptor_pointer[1];
	}
	discriptor_pointer = discriptor_pointer2;

	while(left_len > 0)
	{
		es_info_len = ((discriptor_pointer[3]&0x03)<<8)  | discriptor_pointer[4];
		loop_length = es_info_len;
		discriptor_pointer += 5;
		
		while(loop_length > 0)
		{
			/*the CA descriptor tag*/
			if (*discriptor_pointer == 0x09)
			{
				ecm_pid = ((discriptor_pointer[4]&0x1F)<<8)|discriptor_pointer[5];
				psi_pmt_crc_value = crc_value;

				if(ecm_count<32)
				{
					ecm_pid_array[ecm_count] = ecm_pid;
					ecm_count++;
				}
				else
					libc_printf("ecm_count: %d, count > 32 \n",ecm_count);
			}
			loop_length -= 2+discriptor_pointer[1];
			discriptor_pointer += 2+discriptor_pointer[1];
		}
		left_len -= 5+es_info_len;
	}
	
	return;
}


//#endif
#endif

#ifdef AUTO_OTA
/*******************************************************************************
*   Funtion name : get_ssuinfo_from_pmt()
*   Description:
*       1. search effect otainfo in pmt.
*       2. *pssu_pid: if find, this value to send its value.
*       3. return value: if find effect otainfo, return SUCCESS.
*   Time: 20080421
*******************************************************************************/
INT32 get_ssuinfo_from_pmt(struct program_map *map, UINT16 *pssu_pid, UINT16 pmtpid)
{
	INT32 ret = !SI_SUCCESS;
	UINT32 i = 0;

//	for(i=0; i< psi_info->pmt_counter; i++)
	{
//		if (pmtpid != 0)
		{
//			if(psi_info->maps[i].pm_info.pmt_pid != pmtpid)
//				continue;
		}
		
		PROG_INFO *pmt_section_info = &map->pm_info;
		AUTO_OTA_INFO *pts_ota_info = &map->pm_info.p_esloopinfo.pmt_ssu_info.m_otainfo;

		if(0 != pmt_section_info->p_esloopinfo.pmt_ssu_info.ssu_pid)
		{
			if(si_get_otaconfig_oui() == pmt_section_info->p_esloopinfo.pmt_ssu_info.m_otainfo.oui)
			{
#ifdef DVBS_SUPPORT
				if(si_get_ota_ssupid_s() != pmt_section_info->p_esloopinfo.pmt_ssu_info.ssu_pid)
					si_set_ota_ssupid_s(pmt_section_info->p_esloopinfo.pmt_ssu_info.ssu_pid);
#endif
#if(defined( DVBT_SUPPORT)||defined(ISDBT_SUPPORT))
				if(si_get_ota_ssupid_t() != pmt_section_info->p_esloopinfo.pmt_ssu_info.ssu_pid)
					si_set_ota_ssupid_t(pmt_section_info->p_esloopinfo.pmt_ssu_info.ssu_pid);
#endif
				INT32 otaret;
				struct section_param sec_param;
				sec_param.section_type = 0x00;
				otaret = si_private_sec_parsing_start(0,
					pmt_section_info->p_esloopinfo.pmt_ssu_info.ssu_pid,
					parse_dsmcc_sec,
					(void*)(&sec_param));	
				if(otaret == OTA_SUCCESS)
				{
					*pssu_pid = pmt_section_info->p_esloopinfo.pmt_ssu_info.ssu_pid;
					ret = SI_SUCCESS;
				}
			}
		}
	}
	return ret;
}
#endif

